package com.njit.aoip;
import com.njit.aoip.DB.DB;
import com.njit.aoip.model.IPModel;
import com.njit.aoip.utils.DemoScrollBarUI;
import jpcap.JpcapCaptor;
import jpcap.NetworkInterface;
import jpcap.packet.*;

import javax.swing.*;
import javax.swing.border.LineBorder;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.io.IOException;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class AnalyseIP extends JFrame{

    private List<IPModel> ipModelList;
    private JpcapCaptor jpCap = null;
    private JTree ipTree;
    private DefaultTreeModel ipTreeModel;
    //根结点
    private DefaultMutableTreeNode root;
    private Thread thread;
    private boolean flag = true;
    private int currentProgress=0;
    private JProgressBar progressBar;
    private int countNum=0;
    private int seletor=-1;
    //绑定网络设备
    private NetworkInterface[] devices;
    private AnalyseIP(){
        super("解析ip数据包的设计");
        //初始化三个表
        ipModelList = new ArrayList<>();
//        Enumeration<java.net.NetworkInterface> a = null;
//        try {
//            a = getNetworkInterfaces();
//        } catch (SocketException e) {
//            e.printStackTrace();
//        }
//        List<String>networkInterfaces = new ArrayList<>();
//        assert a != null;
//        while(a.hasMoreElements()){
//            networkInterfaces.add(a.nextElement().getDisplayName());
//        }
        //绑定网络设备
        devices = JpcapCaptor.getDeviceList();
        //默认选择无线网
        setProperJpCap(devices[0]);

        this.setSize(1000, 600);
        this.setLocationRelativeTo(null);
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        JPanel panel = new JPanel();

        //设置字体
        Font font = new Font("黑体", Font.BOLD, 18);

        JPanel toolBarPanel = new JPanel();
        toolBarPanel.setBounds(50,15,900,40);
        toolBarPanel.setLayout(new FlowLayout(FlowLayout.LEADING,10,0));

        //进度条
        progressBar = new JProgressBar();
        // 设置进度的 最小值 和 最大值
        progressBar.setMinimum(0);
        progressBar.setMaximum(100);
        // 设置当前进度值
        progressBar.setValue(0);
        // 绘制百分比文本（进度条中间显示的百分数）
        progressBar.setStringPainted(true);
        progressBar.setBounds(200,500,300,20);
        progressBar.setVisible(false);

        panel.add(progressBar);

        //下拉列表(4台设备)
        String[] listData = new String[]{devices[0].description, devices[1].description, devices[2].description, devices[3].description};
        JComboBox<String> comboBox_device = new JComboBox<>(listData);
        comboBox_device.setFont(font);
        comboBox_device.setSelectedIndex(0);
        //下拉列表
        String[] listData2 = new String[]{"全部","TCP","UDP","ICMP"};
        JComboBox<String> comboBox_protocol = new JComboBox<>(listData2);
        comboBox_protocol.setFont(font);
        comboBox_protocol.setSelectedIndex(0);

        //清空数据
        JButton clear = new JButton("清空数据");
        clear.setFont(font);

        //累计抓包计数器
        JLabel counterLabel = new JLabel("累计抓包");
        counterLabel.setFont(font);
        JLabel counter = new JLabel("0");
        counter.setFont(font);

        toolBarPanel.add(comboBox_device);
        toolBarPanel.add(comboBox_protocol);
        toolBarPanel.add(clear);
        toolBarPanel.add(counterLabel);
        toolBarPanel.add(counter);

        panel.add(toolBarPanel);

        //按钮组
        JPanel buttons = new JPanel();
        buttons.setBounds(680,60,250,400);
        buttons.setLayout(new FlowLayout(FlowLayout.LEADING,10,20));

        JLabel label1 = new JLabel("SRC_IP");
        label1.setFont(font);
        label1.setSize(50,25);
        label1.setVisible(false);
        JTextField sourceIPText = new JTextField("000.000.000.000");
        sourceIPText.setFont(font);
        sourceIPText.setSize(100,25);
        sourceIPText.setVisible(false);

        JLabel label2 = new JLabel("DST_IP");
        label2.setFont(font);
        label2.setSize(50,25);
        label2.setVisible(false);
        JTextField dstIPText = new JTextField("000.000.000.000");
        dstIPText.setFont(font);
        dstIPText.setSize(100,25);
        dstIPText.setVisible(false);


        JButton threadCatch = new JButton("线程抓包");
        threadCatch.setFont(font);
        JButton stopCatch = new JButton("停止抓包");
        stopCatch.setFont(font);
        JSlider slider = new JSlider(0,1000);
        slider.setValue(500);
        // 设置主刻度间隔
        slider.setMajorTickSpacing(200);
        // 设置次刻度间隔
        slider.setMinorTickSpacing(1);
        // 绘制 刻度 和 标签
        slider.setPaintTicks(true);
        slider.setPaintLabels(true);
        JButton numCatch = new JButton("个数抓包");
        numCatch.setFont(font);
        JTextField numText = new JTextField("500");
        numText.setFont(font);
        JButton store = new JButton("存储数据");
        store.setFont(font);
        JButton view = new JButton("查看历史");
        view.setFont(font);
        view.setVisible(false);

        buttons.add(label1);
        buttons.add(sourceIPText);
        buttons.add(label2);
        buttons.add(dstIPText);
        buttons.add(threadCatch);
        buttons.add(stopCatch);
        buttons.add(slider);
        buttons.add(numCatch);
        buttons.add(numText);
        buttons.add(store);
        buttons.add(view);

        panel.add(buttons);

        root = new  DefaultMutableTreeNode( "ip包" ,  true );
        //创建一棵树的根结点(初始为空)
        ipTreeModel = new DefaultTreeModel(root);
        //装入根结点
        ipTree  =   new  JTree (ipTreeModel);
        ipTree.setShowsRootHandles(true);
        ipTree.setRootVisible(false);
        ipTree.setFont(font);

        JScrollPane scrollPane = new JScrollPane(ipTree, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        scrollPane.setBounds(60,60,600,400);
        beautifyScrollPane(scrollPane);
        panel.add(scrollPane);
        panel.setLayout(null);
        panel.setOpaque(false);
        this.setContentPane(panel);
        this.setVisible(true);

        //进度条监听器
        progressBar.addChangeListener(e -> {
            if(progressBar.getValue()==100){
                progressBar.setVisible(false);
                currentProgress=0;
            }
        });

        // 网卡设备选中监听器
        comboBox_device.addItemListener(e -> {
            // 只处理选中的状态
            if (e.getStateChange() == ItemEvent.SELECTED) {
                int index = comboBox_device.getSelectedIndex();
                setProperJpCap(devices[index]);
            }
        });
        // 筛选内部协议监听器
        comboBox_protocol.addItemListener(e -> {
            // 只处理选中的状态
            if (e.getStateChange() == ItemEvent.SELECTED) {
                int index = comboBox_protocol.getSelectedIndex();
                if(index==0)
                    seletor = -1;//全部
                else if(index==1)
                    seletor = 6;//TCP
                else if(index==2)
                    seletor = 17;//UDP
                else if(index==3)
                    seletor = 1;
            }
        });

        //清空数据
        clear.addActionListener(e -> {
            countNum = 0;
            currentProgress=0;
            progressBar.setVisible(false);
            root = new  DefaultMutableTreeNode( "ip包" ,  true );
            ipModelList = new ArrayList<>();
            //创建一棵树的根结点(初始为空)
            ipTreeModel = new DefaultTreeModel(root);
            ipTree.setModel(ipTreeModel);
            ipTreeModel.reload();
        });


        //线程抓包监听器
        threadCatch.addActionListener(e -> {
            flag = true;
            threadCatch.setEnabled(false);
            thread = new Thread (() -> {
                while(flag){
                    try {
                        Packet packet = getPacket(jpCap,seletor);
                        DefaultMutableTreeNode node = getIPNode(packet);
                        ipTreeModel = (DefaultTreeModel) ipTree.getModel();
                        root = (DefaultMutableTreeNode)ipTreeModel.getRoot();
                        root.add(node);
                        countNum++;
                        //下面语句为了刷新界面
                        ipTree.setModel(ipTreeModel);
                        ipTreeModel.reload();
                        //0.1s抓一个包
                        Thread.sleep(100);
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }
                }
            });
            thread.start();
        });

        //停止抓包监听器
        stopCatch.addActionListener(e ->{
            thread.stop();
            flag = false;
            threadCatch.setEnabled(true);
        });

        //个数抓包监听器
        numCatch.addActionListener(e -> {
            String numStr = numText.getText();
            int num;
            try{
                num = Integer.parseInt(numStr);
                if(num>0&&num<=1000){
                    clear.setEnabled(false);
                    threadCatch.setEnabled(false);
                    stopCatch.setEnabled(false);
                    store.setEnabled(false);
                    numCatch.setEnabled(false);
                    numText.setEnabled(false);
                    slider.setEnabled(false);
                    new Thread (() -> {
                        progressBar.setVisible(true);
                        for(int i = 0;i < num;i++){
                            try {
                                Packet packet = getPacket(jpCap,seletor);
                                DefaultMutableTreeNode node = getIPNode(packet);
                                ipTreeModel = (DefaultTreeModel) ipTree.getModel();
                                root = (DefaultMutableTreeNode)ipTreeModel.getRoot();
                                root.add(node);
                                countNum++;
                                //下面语句为了刷新界面
                                ipTree.setModel(ipTreeModel);
                                ipTreeModel.reload();
                                //0.1s抓一个包
                                Thread.sleep(10);
                                currentProgress=(i+1)*100/num;
                            } catch (InterruptedException e1) {
                                e1.printStackTrace();
                            }
                        }
                        clear.setEnabled(true);
                        threadCatch.setEnabled(true);
                        stopCatch.setEnabled(true);
                        store.setEnabled(true);
                        numCatch.setEnabled(true);
                        numText.setEnabled(true);
                        slider.setEnabled(true);
                    }).start();
                }else if(num<=0){
                    JOptionPane.showMessageDialog(null,"个数在1~1000!");
                    numText.setText("500");
                }else{
                    JOptionPane.showMessageDialog(null,"个数在1~1000!");
                    numText.setText("500");
                }
            }catch (NumberFormatException nf){
                JOptionPane.showMessageDialog(null,"请输入整数!");
                numText.setText("500");
            }
        });

        slider.addChangeListener(e -> numText.setText(slider.getValue()+""));

        //存储数据监听器
        store.addActionListener(e -> {
            if(ipTreeModel.isLeaf(ipTreeModel.getRoot())){
                JOptionPane.showMessageDialog(null,"插入空值!");
            }else{
               insertAll(ipModelList);
            }
        });

        //查看历史监听器
        view.addActionListener(e -> {

        });

        // 模拟延时操作进度, 每隔 0.1秒更新进度
        new Timer(100, e ->{
            progressBar.setValue(currentProgress);
            counter.setText(countNum+"");
        }).start();

    }
    /**
     * @description: 设置合适的网卡
     * @author: yuruiqiao
     * @date: 2020/9/18
     */
    private void setProperJpCap(NetworkInterface device){
        try {
            //选择合适的网卡,这里只有这个网卡才能捕获
            jpCap = JpcapCaptor.openDevice(device, 1512, true, 50);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * @description: 获取协议的字符串形式
     * @author: yuruiqiao
     * @date: 2020/9/15
     */
    private  String getProtocol(int protocol){
        String protocolstr = "";
        switch (protocol) {
            case 1: protocolstr = "ICMP";break;
            case 2:protocolstr = "IGMP";break;
            case 6:protocolstr = "TCP";break;
            case 8: protocolstr = "EGP";break;
            case 9:protocolstr = "IGP";break;
            case 17:protocolstr = "UDP";break;
            case 41:protocolstr = "IPv6";break;
            case 89:protocolstr = "OSPF";break;
            default:break;
        }
        return protocolstr;
    }
    /**
     * @description: 用于捕获一个包
     * @author: yuruiqiao
     * @date: 2020/9/15
     */
    private Packet getPacket(JpcapCaptor jpCap,int selector){
        //开始循环抓包
        assert jpCap != null;
        Packet packet= jpCap.getPacket();
        //直到找到ip包(并且筛选内部协议比如TCP,UDP)
        if(selector==-1){
            //默认情况,不筛选内部协议,selector=-1
            while (!(packet instanceof IPPacket) || ((IPPacket) packet).version != 4)
                packet = jpCap.getPacket();
        }else{
            //当selector不为-1表示筛选了内部协议
            while (!(packet instanceof IPPacket) || ((IPPacket) packet).version != 4||((IPPacket) packet).protocol !=selector )
                packet = jpCap.getPacket();
        }
        //这里已经找到ip包了
        IPPacket ip = (IPPacket) packet;
        //自己的一个ip对象
        IPModel ipModel = new IPModel();
        ipModel.setIpVersion(4);
        //优先权
        ipModel.setPriority(ip.priority);
        //区分服务：最大的吞吐量
        ipModel.setTFlag(ip.t_flag);
        //区分服务：最高的可靠性
        ipModel.setRFlag(ip.r_flag);
        //首部长度
        ipModel.setHeaderLength(ip.header.length);
        //总长度
        ipModel.setTotalLength(ip.length);
        //标识
        ipModel.setIdentification(ip.ident);
        //DF
        ipModel.setDf(ip.dont_frag);
        //MF
        ipModel.setMf(ip.more_frag);
        //片偏移
        ipModel.setOffSet(ip.offset);
        //生存时间
        ipModel.setTtl(ip.hop_limit);
        //协议
        ipModel.setProtocol(getProtocol(ip.protocol));
        //源ip
        ipModel.setSourceIP(ip.src_ip.getHostAddress());
        //目的ip
        ipModel.setDestinationIP(ip.dst_ip.getHostAddress());
        ipModelList.add(ipModel);

        return packet;
    }

    /**
     * @description: 执行SQL语句插入所有的ip包
     * @author: yuruiqiao
     * @date: 2020/9/16
     */
    private void insertAll(List<IPModel> ipModels) {
        String sql = "insert into IPModel(ipVersion,priority,TFlag,RFlag,headerLength,totalLength,identification,df,mf,offSet,ttl,protocol,sourceIP,destinationIP)" +
                " values(?,?,?,?,?,?,?,?,?,?,?,?,?,?);";
        DB db = new DB();
        try {
            PreparedStatement ps = db.PreparedStatement(sql);
            //非空判断
            if (ipModels.size()==0){
                JOptionPane.showMessageDialog(null,"插入空值!");
                return;
            }
            if(ipModels.size()>100){
                JOptionPane.showMessageDialog(null,"插入个数过多!");
                return;
            }

            for (IPModel ipModel : ipModels) {
                ps.setInt(1, ipModel.getIpVersion());
                ps.setInt(2, ipModel.getPriority());
                ps.setBoolean(3, ipModel.isTFlag());
                ps.setBoolean(4, ipModel.isRFlag());
                ps.setInt(5, ipModel.getHeaderLength());
                ps.setInt(6, ipModel.getTotalLength());
                ps.setInt(7, ipModel.getIdentification());
                ps.setBoolean(8, ipModel.isDf());
                ps.setBoolean(9, ipModel.isMf());
                ps.setInt(10, ipModel.getOffSet());
                ps.setInt(11, ipModel.getTtl());
                ps.setString(12, ipModel.getProtocol());
                ps.setString(13, ipModel.getSourceIP());
                ps.setString(14, ipModel.getDestinationIP());
                ps.execute();
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    /**
     * @description: 生成一个ip结点
     * @author: yuruiqiao
     * @date: 2020/9/16
     */
    private DefaultMutableTreeNode getIPNode(Packet packet){
        DefaultMutableTreeNode ipNode;
        //进入到这一步说明抓到ip包了
        IPPacket ip = (IPPacket) packet;
        ipNode = new DefaultMutableTreeNode("IPV4 SRC: " + ip.src_ip.getHostAddress() + " DST: " + ip.dst_ip.getHostAddress());
        ipNode.add(new DefaultMutableTreeNode("IP版本号---" + ip.version));
        ipNode.add(new DefaultMutableTreeNode("优先权---" + ip.priority));
        ipNode.add(new DefaultMutableTreeNode("最大吞吐量---" + ip.t_flag));
        ipNode.add(new DefaultMutableTreeNode("最高可靠性---" + ip.r_flag));
        ipNode.add(new DefaultMutableTreeNode("头部长度---" + ip.header.length));
        ipNode.add(new DefaultMutableTreeNode("总长度---" + ip.length));
        ipNode.add(new DefaultMutableTreeNode("标识---" + ip.ident));
        ipNode.add(new DefaultMutableTreeNode("DF---" + ip.d_flag));
        ipNode.add(new DefaultMutableTreeNode("MF---" + ip.more_frag));
        ipNode.add(new DefaultMutableTreeNode("片偏移---" + ip.offset));
        ipNode.add(new DefaultMutableTreeNode("TTL---" + ip.hop_limit));
        ipNode.add(new DefaultMutableTreeNode("协议---" + getProtocol(ip.protocol)));
        ipNode.add(new DefaultMutableTreeNode("源ip---" + ip.src_ip.getHostAddress()));
        ipNode.add(new DefaultMutableTreeNode("目的ip---" + ip.dst_ip.getHostAddress()));
        //子包结点(TCP,UDP等等)
        DefaultMutableTreeNode ipSubNode;
        if (packet instanceof TCPPacket) {
            TCPPacket tcpPacket = (TCPPacket)packet;
            ipSubNode = new DefaultMutableTreeNode("TCP SRC Port: " + tcpPacket.src_port + " DST Port: " + tcpPacket.dst_port);
            ipSubNode.add(new DefaultMutableTreeNode("源端口---" + tcpPacket.src_port));
            ipSubNode.add(new DefaultMutableTreeNode("目的端口---" + tcpPacket.dst_port));
            ipSubNode.add(new DefaultMutableTreeNode("ack---" + tcpPacket.ack));
            ipSubNode.add(new DefaultMutableTreeNode("ack_num---" + tcpPacket.ack_num));
            ipSubNode.add(new DefaultMutableTreeNode("fin---" + tcpPacket.fin));
            ipSubNode.add(new DefaultMutableTreeNode("sequence---" + tcpPacket.sequence));
            ipSubNode.add(new DefaultMutableTreeNode("urgent_pointer---" + tcpPacket.urgent_pointer));
            ipNode.add(ipSubNode);
        } else if (packet instanceof UDPPacket) {
            UDPPacket udpPacket = (UDPPacket)packet;
            ipSubNode = new DefaultMutableTreeNode("UDP SRC Port: " + udpPacket.src_port + " DST Port: " + udpPacket.dst_port);
            ipSubNode.add(new DefaultMutableTreeNode("源端口---" + udpPacket.src_port));
            ipSubNode.add(new DefaultMutableTreeNode("目的端口---" + udpPacket.dst_port));
            ipSubNode.add(new DefaultMutableTreeNode("长度---" + udpPacket.length));
            ipNode.add(ipSubNode);
        }
        else if (packet instanceof ICMPPacket) {
            ICMPPacket icmpPacket = (ICMPPacket)packet;
            ipSubNode = new DefaultMutableTreeNode("ICMP");
            //请求报文
            if(icmpPacket.type==8 && icmpPacket.code==0)
                ipSubNode = new DefaultMutableTreeNode("ICMP:echo(ping)request ");
            else if(icmpPacket.type==0 && icmpPacket.code==0)
                ipSubNode = new DefaultMutableTreeNode("ICMP:echo(ping)reply ");
            ipSubNode.add(new DefaultMutableTreeNode("alive-time---"+icmpPacket.alive_time));
            ipSubNode.add(new DefaultMutableTreeNode("校验和---"+icmpPacket.checksum));
            ipSubNode.add(new DefaultMutableTreeNode("MTU---"+icmpPacket.mtu));
            ipSubNode.add(new DefaultMutableTreeNode("初始时间---"+icmpPacket.orig_timestamp));
            ipSubNode.add(new DefaultMutableTreeNode("接收时间---"+icmpPacket.recv_timestamp));
            ipNode.add(ipSubNode);
        }
        return ipNode;
    }
    /**
     * @description: 美化滚动条
     * @author: yuruiqiao
     * @date: 2020/9/17
     */
    private void beautifyScrollPane(JScrollPane scrollPane){
        scrollPane.setBorder(new LineBorder(null,0));
        scrollPane.getVerticalScrollBar().setUI(new DemoScrollBarUI());
    }

    /**
     * @description: 程序入口
     * @date: 2020/9/15
     */
    public static void main(String[] args) {
        new AnalyseIP();
    }
}
